/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.shuyihui.rxhttp.func

import android.text.TextUtils
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.shuyihui.rxhttp.model.ApiResult
import com.shuyihui.rxhttp.utils.Utils
import okhttp3.ResponseBody
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.lang.reflect.Modifier
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

/**
 *
 * 描述：定义了ApiResult结果转换Func
 */
class ApiResultFunc<T>(val type: Type) : io.reactivex.functions.Function<ResponseBody?, ApiResult<T>> {
//    protected var type: Type = type
    var gson: Gson = GsonBuilder()
        .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
        .serializeNulls() //                .registerTypeAdapter(String.class, new StringConverter())
        .create()

    override fun apply(responseBody: ResponseBody): ApiResult<T> ?{
        var apiResult = ApiResult<T>()
        apiResult.setCode(-1)
        if (type is ParameterizedType) { //自定义ApiResult
            val cls: Class<T> = (type as ParameterizedType).rawType as Class<T>
            if (ApiResult::class.java.isAssignableFrom(cls)) {
                val params = (type as ParameterizedType).actualTypeArguments
                val clazz = Utils.getClass(params[0], 0)
                val rawType = Utils.getClass(type, 0)
                try {
                    val json = responseBody.string()
                    //增加是List<String>判断错误的问题
                    if (!MutableList::class.java.isAssignableFrom(rawType) && clazz == String::class.java) {
                        apiResult.setData(json as T)
                        apiResult.setCode(0)
                        /* final Type type = Utils.getType(cls, 0);
                        ApiResult result = gson.fromJson(json, type);
                        if (result != null) {
                            apiResult = result;
                            apiResult.setData((T) json);
                        } else {
                            apiResult.setMsg("json is null");
                        }*/
                    } else {
                        val result = gson.fromJson<ApiResult<T>>(json, type)
                        if (result != null) {
                            apiResult = result
                        } else {
                            apiResult.msg = "json is null"
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    apiResult.msg = e.message
                } finally {
                    responseBody.close()
                }
            } else {
                apiResult.msg = "ApiResult.class.isAssignableFrom(cls) err!!"
            }
        } else { //默认Apiresult
            try {
                val json = responseBody.string()
                val clazz: Class<T> = Utils.getClass(type, 0) as Class<T>
                if (clazz == String::class.java) {
                    //apiResult.setData((T) json);
                    //apiResult.setCode(0);
                    val result = parseApiResult(json, apiResult)
                    if (result != null) {
                        apiResult = result
                        apiResult.setData(json as T)
                    } else {
                        apiResult.msg = "json is null"
                    }
                } else {
                    val result = parseApiResult(json, apiResult)
                    if (result != null) {
                        apiResult = result
                        if (apiResult.data != null) {
                            val data = gson.fromJson(apiResult.data.toString(), clazz)
                            apiResult.setData(data)
                        } else {
                            apiResult.msg = "ApiResult's data is null"
                        }
                    } else {
                        apiResult.msg = "json is null"
                    }
                }
            } catch (e: JSONException) {
                e.printStackTrace()
                apiResult.msg = e.message
            } catch (e: IOException) {
                e.printStackTrace()
                apiResult.msg = e.message
            } finally {
                responseBody.close()
            }
        }
        return apiResult
    }

    @Throws(JSONException::class)
    private fun parseApiResult(json: String, apiResult: ApiResult<T>): ApiResult<T>? {
        if (TextUtils.isEmpty(json)) return null
        val jsonObject = JSONObject(json)
        if (jsonObject.has("code")) {
            apiResult.setCode(jsonObject.getInt("code"))
        }
        if (jsonObject.has("data")) {
            apiResult.setData(jsonObject.getString("data") as Nothing)
        }
        if (jsonObject.has("msg")) {
            apiResult.msg = jsonObject.getString("msg")
        }
        return apiResult
    }


}